package com.unibuy.smartdevice.ui.dialog;

import android.content.Context;
import android.graphics.Color;

import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.work.BackoffPolicy;
import androidx.work.ExistingWorkPolicy;
import androidx.work.OneTimeWorkRequest;
import androidx.work.WorkManager;

import com.unibuy.smartdevice.DialogAbstract;
import com.unibuy.smartdevice.MyApp;
import com.unibuy.smartdevice.R;
import com.unibuy.smartdevice.controller.DevController;
import com.unibuy.smartdevice.controller.DevDigitalDisplayController;
import com.unibuy.smartdevice.controller.DevElectricController;
import com.unibuy.smartdevice.controller.DevFlowerController;
import com.unibuy.smartdevice.database.SlotsDao;
import com.unibuy.smartdevice.databinding.DialogDispatchBinding;
import com.unibuy.smartdevice.devices.ComPort;
import com.unibuy.smartdevice.devices.PortTools;
import com.unibuy.smartdevice.devices.SlotField;
import com.unibuy.smartdevice.exception.ErrorCode;
import com.unibuy.smartdevice.exception.LogsEmptyException;
import com.unibuy.smartdevice.exception.LogsIOException;
import com.unibuy.smartdevice.exception.LogsParseException;
import com.unibuy.smartdevice.exception.LogsSecurityException;
import com.unibuy.smartdevice.exception.LogsSettingEmptyException;
import com.unibuy.smartdevice.exception.LogsUnsupportedOperationException;
import com.unibuy.smartdevice.external.HttpAPI;
import com.unibuy.smartdevice.structure.BuyStructure;
import com.unibuy.smartdevice.structure.DispatchStructure;
import com.unibuy.smartdevice.structure.ProductStructure;
import com.unibuy.smartdevice.structure.ReportDispatchInfoStructure;
import com.unibuy.smartdevice.structure.ReportFreeGiftCodeStructure;
import com.unibuy.smartdevice.structure.SlotStructure;
import com.unibuy.smartdevice.tools.HandlerMainCountdown;
import com.unibuy.smartdevice.tools.HandlerMain;
import com.unibuy.smartdevice.tools.ToastHandlerMain;
import com.unibuy.smartdevice.ui.FontendActivity;
import com.unibuy.smartdevice.ui.recycler.RecyclerDialogDispatchListAdpter;
import com.unibuy.smartdevice.ui.tools.ImageGlide;
import com.unibuy.smartdevice.ui.tools.StringRefactoring;

import org.json.JSONException;
import org.json.JSONObject;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.concurrent.TimeUnit;

public class DispatchDialog extends DialogAbstract {
    public enum Option {
        TOAST(0),
        COUNTDOWN_CANCEL(1),
        SET_COUNTDOWN_TEXT(2),
        NEXT_PRODUCT(3),
        ENABLED_TRUE(4),
        ENABLED_FALSE(5),
        REPORT_DISPATCH(8),
        SET_MESSAGE_TEXT(9),
        CURRENTLY_PROCESSING_GOODS(71),
        SHIPPED_PROCESSING_GOODS(72),
        NEXT_PROCESS_GOODS(73),
        ERROR_PROCESS_GOODS(74),
        ;

        private int option;

        public int getOption() {
            return option;
        }

        Option(int option) {
            this.option = option;
        }
    }

    public static final Map<Integer, Option> optionMap = new HashMap<>();
    static {
        for (Option option : Option.values()) {
            optionMap.put(option.getOption(), option);
        }
    }

    @Override
    protected Context setCtx() {
        return getContext();
    }

    @Override
    protected Class<? extends DialogAbstract> setCls() {
        return getClass();
    }

    @Override
    protected HandlerMain setHandlerMain() {
        return new ToastHandlerMain(getCtx(), getLogs()) {

            @Override
            protected void execute(Context context, int commandCode, String message) {
                if (!optionMap.containsKey(commandCode)) {
                    getLogs().debug("key not found:" + commandCode);
                    return;
                }

                Option option = optionMap.get(commandCode);

                switch (option) {
                    case TOAST:
                        super.execute(context, commandCode, message);
                        break;
                    case COUNTDOWN_CANCEL:
                        cancelOnThreadCountdown();
                        break;
                    case SET_COUNTDOWN_TEXT:
                        setButtonOkText(Integer.parseInt(message));
                        if (Integer.parseInt(message) <= 15) {
                            setTextViewCountdown(Integer.parseInt(message));
                        }
                        break;
                    case NEXT_PRODUCT:
                        currentlyProcessingGoods();
                        break;
                    case ENABLED_TRUE:
                        openButtonOk();
                        break;
                    case ENABLED_FALSE:
                        closeButtonOk();
                        break;
                    case REPORT_DISPATCH:
                        if (isReportDispatch) {
                            try {
                                isReportDispatch = false;
                                new HttpAPI(getHandlerMain()).reportDispatchInfo(MyApp.getInstance().getReportDispatchInfoData());
                            } catch (LogsSettingEmptyException | LogsParseException e) {
                                getLogs().warning(e);
                            }
                        }
                        break;
                    case SET_MESSAGE_TEXT:
                        setTextViewSmall(message);
                        break;
                    case CURRENTLY_PROCESSING_GOODS:
                        currentlyProcessingGoods();
                        break;
                    case SHIPPED_PROCESSING_GOODS:
                        shippedProcessingGoods();
                        break;
                    case NEXT_PROCESS_GOODS:
                        nextProcessGoods();
                        break;
                    case ERROR_PROCESS_GOODS:
                        if (!buttonControlCountdown.isShutdown()) {
                            buttonControlCountdown.shutdown();
                        }
                        buttonControlCountdown.start(10);

                        closeDialogCountdown.shutdown();
                        setTextViewSmall(message);
                        setButtonOkText(0);
                        break;
                }
            }
        };
    }

    private DialogDispatchBinding binding;
    private RecyclerDialogDispatchListAdpter recyclerDialogDispatchListAdpter;
    private CloseDialogOnThreadHandler closeDialogCountdown;
    private List<DispatchStructure> dispatchList;
    private int dispatchIndex;
    private boolean isReportDispatch;
    private boolean isChangeStatus;
    private int countdownNumber = 60;
    private HandlerMainCountdown buttonControlCountdown;
    private HttpAPI httpAPI;

    public DispatchDialog(Context context, HandlerMain srcHandlerMain) {
        super(context, srcHandlerMain);
        dispatchList = new ArrayList<>();
        dispatchIndex = 0;
        isReportDispatch = true;
        isChangeStatus = true;
    }

    @Override
    protected void onCreate(Context context) {
        binding = DialogDispatchBinding.inflate(getLayoutInflater());
        setContentView(binding.getRoot());
        isReportDispatch = true;
        httpAPI = new HttpAPI(getHandlerMain());

        MyApp.getInstance().setReportFreeGiftCodeStructure(new ReportFreeGiftCodeStructure("", 0, "", 0, 0, ""));

        getLogs().info("BuyList size:" + MyApp.getInstance().getBuyList().size());

        for (BuyStructure buyStructure:  MyApp.getInstance().getBuyList()) {
            getLogs().info(buyStructure.toString());
            if (!buyStructure.getProduct().getMaterialCode().isEmpty() && buyStructure.getProduct().getMaterialCode().contains(":")) {
                String[] materialCodes = buyStructure.getProduct().getMaterialCode().split(":");
                String productId = materialCodes[0];
                int count = Integer.parseInt(materialCodes[1]);
                try {
                    SlotStructure slotData = MyApp.getInstance().getSlotData(buyStructure.getField(), buyStructure.getSlot());
                    if (slotData.getProduct().getProductID().equals(productId)) {
                        DispatchStructure dispatchData = new DispatchStructure(buyStructure.getField(), buyStructure.getSlot(), slotData.getProduct(), count*buyStructure.getCount());
                        dispatchData.setFreeGift(buyStructure.isFreeGift());
                        this.dispatchList.add(dispatchData);
                    }
                } catch (LogsEmptyException e) {
                    getLogs().warning(e);
                }
            } else {
                DispatchStructure dispatchData = new DispatchStructure(buyStructure.getField(), buyStructure.getSlot(), buyStructure.getProduct(), buyStructure.getCount());
                dispatchData.setFreeGift(buyStructure.isFreeGift());
                this.dispatchList.add(dispatchData);
            }
        }

        getLogs().info("DispatchList size:" + this.dispatchList.size());

        this.recyclerDialogDispatchListAdpter = new RecyclerDialogDispatchListAdpter(getCtx(), this.dispatchList, getHandlerMain());
        this.binding.recyclerDialogDispatchList.setAdapter(recyclerDialogDispatchListAdpter);
        this.binding.recyclerDialogDispatchList.setLayoutManager(new LinearLayoutManager(context));

        this.binding.buttonOk.setOnClickListener(v -> {
            currentlyProcessingGoods();
//            try {
//                openLatticeCabinet();
//            } catch (LogsSecurityException e) {
//                throw new RuntimeException(e);
//            } catch (LogsUnsupportedOperationException e) {
//                throw new RuntimeException(e);
//            } catch (LogsIOException e) {
//                throw new RuntimeException(e);
//            }
        });

        this.binding.buttonCancel.setOnClickListener(v -> {
            getSrcHandlerMain().start(getClass().getSimpleName(), FontendActivity.Option.RESET_DATA.getOption(), "update data");


            getSrcHandlerMain().start(getClass().getSimpleName(), "@"+getCtx().getString(R.string.reported_please_contact_site_for_processing));//已回報，請現場聯絡處理
            dialogCancel();
        });

        setButtonOkText(0);

        closeDialogCountdown = new CloseDialogOnThreadHandler(getHandlerMain());
        buttonControlCountdown = new HandlerMainCountdown(getHandlerMain()) {
            @Override
            protected Class<?> setCls() {
                return getClass();
            }

            @Override
            protected HandlerMain setHandlerMain() {
                return getSrcHandlerMain();
            }

            @Override
            protected void execute(long countdown, HandlerMain handlerMain) {
                if (countdown < 2) {
                    handlerMain.start("devShippedProduct", Option.ENABLED_TRUE.getOption(), "enabled true");
                }
            }

            @Override
            protected void close(HandlerMain handlerMain) {
                handlerMain.start("devShippedProduct", Option.ENABLED_TRUE.getOption(), "enabled true");
            }
        };

        currentlyProcessingGoods();
    }

    private void openLatticeCabinet() throws LogsSecurityException, LogsUnsupportedOperationException, LogsIOException {
        getLogs().info("----- openLatticeCabinet -----");
        dialogCancel();

        DispatchStructure dispatch = this.dispatchList.get(this.dispatchIndex);
        int slot = dispatch.getSlot();
        DevFlowerController devFlowerController = new DevFlowerController(setHandlerMain());
        devFlowerController.devSendCustomCommand(slot);
        devFlowerController.start();
        getLogs().info("開啟格子櫃號"+slot);
    }

    public void closeButtonOk() {
        getLogs().info("關閉按鈕");
        binding.buttonOk.setTextColor(Color.GRAY);
        binding.buttonOk.setEnabled(false);
        binding.buttonOk.setTextColor(Color.GRAY);
        binding.buttonOk.setEnabled(false);
    }

    public void openButtonOk() {
        getLogs().info("開啟按鈕");
        binding.buttonOk.setTextColor(Color.BLACK);
        binding.buttonOk.setEnabled(true);
        binding.buttonOk.setTextColor(Color.BLACK);
        binding.buttonOk.setEnabled(true);
    }

    public void dialogCancel() {
        closeDialogCountdown.shutdown();
        int buyListSize = MyApp.getInstance().getBuyList().size();
        MyApp.getInstance().getBuyList().clear();

        if (buyListSize > 0) {
            recyclerDialogDispatchListAdpter.notifyItemRangeRemoved(0, buyListSize);
        }
        cancel();
    }

    public void cancelOnThreadCountdown() {
        MyApp.getInstance().getBuyList().clear();
        cancel();
    }

    private boolean isCheckSlotByVMC = false;
    private int checkSlotRunCount = 0;

    public class DevCheckSlotByVMC extends DevController.ReadBufferOnScheduler {
        private int slot;

        public DevCheckSlotByVMC(HandlerMain handlerMain, int slot) {
            super(handlerMain);

            this.slot = slot;
        }

        @Override
        protected HandlerMain setHandlerMain() {
            return getSrcHandlerMain();
        }

        @Override
        protected Class<?> setCls() {
            return getClass();
        }

        @Override
        public void readBufferOnScheduler(DevController devController, HandlerMain handlerMain) {
            if (isCheckSlotByVMC) return;

            boolean isCMD = false;
            boolean isSuccess = false;

            for (byte[] buffer: devController.getReadBufferByMax()) {
                if (buffer[0] == 0x02) {
                    getLogs().info("DevCheckSlotByVMC:" + PortTools.showHex(buffer));

                    isCMD = true;
                    if (buffer[1] == 0x01 || buffer[1] == 0x02 || buffer[1] == 0x04) {
                        isSuccess = true;
                        break;
                    }
                }
            }

            getLogs().info("vmc isCMD:" + isCMD + " isSuccess:" + isSuccess);

            if (isCMD) {
                if (isSuccess) {
                    MyApp.getInstance().getDevXinYuanController().getReadBufferByNow(new DevGetProductByVMC(handlerMain, slot), 5000);
                    MyApp.getInstance().getDevXinYuanController().addSendBuffer(MyApp.getInstance().getDevXinYuanController().getDevXinYuan().getProduct(slot));
                    isCheckSlotByVMC = true;
                } else {
                    buttonControlCountdown.shutdown();
                    getSrcHandlerMain().start(getClass().getSimpleName(), Option.ERROR_PROCESS_GOODS.getOption(), getCtx().getString(R.string.check_whether_goods_have_been_taken_out_before_confirming_collection));//請檢查商品有無取出再確認取貨
                }
            } else {
                if (checkSlotRunCount >= 10) {
                    buttonControlCountdown.shutdown();
                    getSrcHandlerMain().start(getClass().getSimpleName(), Option.ERROR_PROCESS_GOODS.getOption(), getCtx().getString(R.string.slave_computer_did_not_respond_wait_3_seconds_try_again));//下位機無回應 請等3秒後再重試
                    checkSlotRunCount = 0;
                } else {
                    MyApp.getInstance().getDevXinYuanController().getReadBufferByNow(new DevCheckSlotByVMC(handlerMain, slot));
                    MyApp.getInstance().getDevXinYuanController().addSendBuffer(MyApp.getInstance().getDevXinYuanController().getDevXinYuan().checkSlot(slot));
                    checkSlotRunCount++;
                }
            }
        }
    }

    private boolean isGetProductByVMC = false;
    private int getProductRunCount = 0;
    public class DevGetProductByVMC extends DevController.ReadBufferOnScheduler {
        private int slot;

        public DevGetProductByVMC(HandlerMain handlerMain, int slot) {
            super(handlerMain);

            this.slot = slot;
        }

        @Override
        protected HandlerMain setHandlerMain() {
            return getSrcHandlerMain();
        }

        @Override
        protected Class<?> setCls() {
            return getClass();
        }

        @Override
        public void readBufferOnScheduler(DevController devController, HandlerMain handlerMain) {
            if (isGetProductByVMC) return;

            boolean isCMD = false;
            boolean inTheMiddle = false;
            boolean isSuccess = false;

            for (byte[] buffer: devController.getReadBufferByMax()) {
                if (buffer[0] == 0x04) {
                    getLogs().info("DevGetProductByVMC:" + PortTools.showHex(buffer));

                    isCMD = true;

                    if (buffer[1] == 0x01) {
                        inTheMiddle = true;
                        isSuccess = true;
                        break;
                    }

                    if (buffer[1] == 0x01 || buffer[1] == 0x10 || buffer[1] == 0x11) {
                        inTheMiddle = true;
                        continue;
                    }

                    if (buffer[1] == 0x02 || buffer[1] == 0x24) {
                        inTheMiddle = true;
                        isSuccess = true;
                        break;
                    }
                }
            }

            getLogs().info("vmc isCMD:" + isCMD + " inTheMiddle:" + inTheMiddle + " isSuccess:" + isSuccess);

            if (isCMD) {
                if (inTheMiddle) {
                    if (isSuccess) {
                        getHandlerMain().start(getClass().getSimpleName(), Option.NEXT_PROCESS_GOODS.getOption(), "next process goods");
                        isGetProductByVMC = true;
                    } else {
                        MyApp.getInstance().getDevXinYuanController().getReadBufferByNow(new DevGetProductByVMC(handlerMain, slot), 5000);
                    }
                } else {
                    buttonControlCountdown.shutdown();
                    getSrcHandlerMain().start(getClass().getSimpleName(), Option.ERROR_PROCESS_GOODS.getOption(), getCtx().getString(R.string.check_whether_goods_have_been_taken_out_before_confirming_collection));//請檢查商品有無取出再確認取貨
                }
            } else {
                if (getProductRunCount >= 10) {
                    buttonControlCountdown.shutdown();
                    getSrcHandlerMain().start(getClass().getSimpleName(), Option.ERROR_PROCESS_GOODS.getOption(), getCtx().getString(R.string.slave_computer_did_not_respond_wait_3_seconds_try_again));//下位機無回應 請等3秒後再重試
                    getProductRunCount = 0;
                } else {
                    MyApp.getInstance().getDevXinYuanController().getReadBufferByNow(new DevGetProductByVMC(handlerMain, slot), 5000);
                    MyApp.getInstance().getDevXinYuanController().addSendBuffer(MyApp.getInstance().getDevXinYuanController().getDevXinYuan().getProduct(slot));
                    getProductRunCount++;
                }
            }
        }
    }

    private void saveData() {
        SlotsDao slotsDao = new SlotsDao(getCtx());
        slotsDao.deleteAll();
        slotsDao.insertAll(MyApp.getInstance().getSlotMap());
        slotsDao.close();
        getLogs().info("save count:"+ MyApp.getInstance().getSlotList(SlotField.VMC.getField()).size());
    }

    public void currentlyProcessingGoods() { //出貨前動作，UI與資料變更
        getLogs().info("----- currentlyProcessingGoods -----");

        if (this.dispatchIndex == -1) { //最後一次確定完後沒有貨要出就關閉視窗
            dialogCancel();
        }

        if (this.dispatchList != null && !this.dispatchList.isEmpty() && this.dispatchIndex > -1) {
            DispatchStructure dispatch = this.dispatchList.get(this.dispatchIndex);
            int field = dispatch.getField();
            int slot = dispatch.getSlot();
            int count = dispatch.getCount();
            int quantity = dispatch.getQuantity();
            boolean isShipped = dispatch.isShipped(); //表記是否是正在出貨
            int increase = 1; //機台要出幾個貨？

            try {
                //出貨數量
                if (SlotField.getSlotField(field).isCanOneShipped()) {
                    increase = 1;
                } else {
                    increase = quantity;
                }
            } catch (LogsEmptyException e) {
                increase = 1;
            }

            ProductStructure product = dispatch.getProduct();

            if (!isShipped) {
                isShipped = true;
                this.dispatchList.get(this.dispatchIndex).setShipped(true);
                this.recyclerDialogDispatchListAdpter.notifyItemChanged(this.dispatchIndex);
            }

            getLogs().info("isShipped:" + isShipped);
            getLogs().info("dispatchIndex:" + dispatchIndex + " dispatchList:" + dispatchList.size());
            getLogs().info("count:" + count +" quantity:" + quantity);

            if (isShipped) { //正在要出貨的話
                if (count < quantity) { //count 目前出了多少貨 Quantity 總貨物數量
                    //設定商品名稱和圖片
                    binding.textProductName.setText(product.getProductName());

                    try {
                        new ImageGlide(getContext()).fileload(product.getProductImg(), binding.imageProductPicture);
                    } catch (LogsEmptyException e) {
                        getLogs().warning(e);
                    }

                    setTextViewCountdown(0);
                    isGetProductByVMC = false;
                    isCheckSlotByVMC = false;
                    checkSlotRunCount = 0;
                    getProductRunCount = 0;
                    isChangeStatus = true;

                    getHandlerMain().start(getClass().getSimpleName(), Option.SHIPPED_PROCESSING_GOODS.getOption(), "shipped processing goods");
                }
            }
        }
    }

    //devShippedProduct(field, slot, increase);
    //出貨中動作
    public void shippedProcessingGoods() {
        getLogs().info("----- shippedProcessingGoods -----");

        if (this.dispatchList != null && !this.dispatchList.isEmpty() && this.dispatchIndex > -1) {
            DispatchStructure dispatch = this.dispatchList.get(this.dispatchIndex);
            int field = dispatch.getField();
            int slot = dispatch.getSlot();
            int count = dispatch.getCount();
            int quantity = dispatch.getQuantity();
            boolean isShipped = dispatch.isShipped(); //表記是否是正在出貨
            int increase = 1; //機台要出幾個貨？

            try {
                //出貨數量
                if (SlotField.getSlotField(field).isCanOneShipped()) {
                    increase = 1;
                } else {
                    increase = quantity;
                }
            } catch (LogsEmptyException e) {
                increase = 1;
            }

            ProductStructure product = dispatch.getProduct();

            getLogs().info("isShipped:" + isShipped);
            getLogs().info("dispatchIndex:" + dispatchIndex + " dispatchList:" + dispatchList.size());
            getLogs().info("count:" + count +" quantity:" + quantity);

            if (isShipped) { //正在要出貨的話
                //控制倒數計時，先倒數再出貨
                try {
                    SlotField slotField = SlotField.getSlotField(field);
                    if (slotField.isAutoNextProduct()) {
                        if (!closeDialogCountdown.isShutdown()) {
                            closeDialogCountdown.shutdown();
                        }
                        closeDialogCountdown.start(countdownNumber);
                    } else {
                        setButtonOkText(0);
                    }
                } catch (LogsEmptyException e) {
                    setButtonOkText(0);
                }

                if (!buttonControlCountdown.isShutdown()) {
                    buttonControlCountdown.shutdown();
                }

                try {
                    closeButtonOk();
                    SlotField slotField = SlotField.getSlotField(field);
                    switch (slotField) {
                        case VMC:
                                devRunVMC(field, slot, increase);
                            break;
                        case ELECTRIC:
                            try {
                                devRunElectric(field, slot, increase);
                            } catch (LogsSecurityException | LogsUnsupportedOperationException | LogsIOException e) {
                                getLogs().warning(e);
                            }

                            break;
                    }
                } catch (LogsEmptyException e) {
                    getLogs().warning(e);
                }
            }
        } else {
            dialogCancel();
        }

        getLogs().info("index:" + this.dispatchIndex);
    }

    private void nextProcessGoods() { //出貨後動作，索引變更和上傳資料
        getLogs().info("----- nextProcessGoods -----");

        if (this.dispatchList != null && !this.dispatchList.isEmpty() && this.dispatchIndex > -1) {
            DispatchStructure dispatch = this.dispatchList.get(this.dispatchIndex);
            int field = dispatch.getField();
            int slot = dispatch.getSlot();
            int count = dispatch.getCount();
            int quantity = dispatch.getQuantity();
            boolean isShipped = dispatch.isShipped(); //表記是否是正在出貨
            int increase = 1; //機台要出幾個貨？
            try {
                //出貨數量
                if (SlotField.getSlotField(field).isCanOneShipped()) {
                    increase = 1;
                } else {
                    increase = quantity;
                }
            } catch (LogsEmptyException e) {
                increase = 1;
            }
            ProductStructure product = dispatch.getProduct();

            getLogs().info("isShipped:" + isShipped);
            getLogs().info("dispatchIndex:" + dispatchIndex + " dispatchList:" + dispatchList.size());
            getLogs().info("count:" + count +" quantity:" + quantity);

            if (isShipped) { //正在要出貨的話，出貨完成後
                if (count < quantity) { //count 目前出了多少貨 Quantity 總貨物數量
                    try {
                        if (SlotField.getSlotField(field).isCanOneShipped()) {  //一個出貨還是一次出貨
                            count += 1; //目前出貨量+將要出1個
                        } else {
                            count = quantity; //要出全部
                        }
                    } catch (LogsEmptyException e) {
                        count += 1;
                    }

                    this.dispatchList.get(this.dispatchIndex).setCount(count);
                    this.recyclerDialogDispatchListAdpter.notifyItemChanged(this.dispatchIndex);
                }

                try {
                    int slotCount = MyApp.getInstance().getSlotData(field, slot).getCount();
                    int remaining = slotCount-increase; //計算剩餘數量
                    MyApp.getInstance().getSlotData(field, slot).setCount(remaining);
                    MyApp.getInstance().getReportDispatchInfoData().setRemaining(remaining);
                } catch (LogsEmptyException e) {
                    getLogs().warning(e);
                }

                //設定回傳資料
                int price = product.getRealPrice() * count;

                MyApp.getInstance().setReportDispatchInfoData(new ReportDispatchInfoStructure(
                        MyApp.getInstance().getReportFlowInfoData().getReportFlowId(),
                        MyApp.getInstance().getReportFlowInfoData().getFlowType(),
                        product.getProductID(),
                        slot,
                        price*increase,
                        MyApp.getInstance().getReportFlowInfoData().getOrderId(),
                        increase,
                        MyApp.getInstance().getReportFlowInfoData().getFlowBarCode(),
                        "",
                        0,
                        price,
                        0
                ));

                isReportDispatch = true;
                if (isReportDispatch) {
                    try {
                        isReportDispatch = false;
                        if (dispatch.isFreeGift()) {
                            MyApp.getInstance().getReportFreeGiftCodeStructure().setSlot(slot);
                            MyApp.getInstance().getReportFreeGiftCodeStructure().setProductId(product.getProductID());
                            MyApp.getInstance().getReportFreeGiftCodeStructure().setMoney(price);
                            httpAPI.reportFreeGiftCode(MyApp.getInstance().getReportFreeGiftCodeStructure());
                        } else {
                            httpAPI.reportDispatchInfo(MyApp.getInstance().getReportDispatchInfoData());
                        }
                    } catch (LogsSettingEmptyException | LogsParseException e) {
                        getLogs().warning(e);
                    }
                }

                getLogs().info("count:" + count +" quantity:" + quantity);

                if (count == quantity) { //貨物是否已經出貨完畢
                    //偵測是否還有下個出貨商品
                    if (this.dispatchIndex >= this.dispatchList.size()-1) { //沒有貨
                        this.dispatchIndex = -1;

                        getSrcHandlerMain().start(getClass().getSimpleName(), FontendActivity.Option.RESET_DATA.getOption(), "update data");
                        saveData();
                    } else { //有貨要出了
                        this.dispatchIndex += 1; //表記下一個商品要出貨
                    }
                }
            }
        }
    }

    private void devRunVMC(int field, int slot, int increase) {
        if (buttonControlCountdown.isShutdown()) {
            buttonControlCountdown.start(25);
        } else {
            buttonControlCountdown.setCountdown(25);
        }

        getLogs().info("11111");
        MyApp.getInstance().getDevXinYuanController().getReadBufferByNow(new DevCheckSlotByVMC(getHandlerMain(), slot));
        getLogs().info("22222");
        MyApp.getInstance().getDevXinYuanController().addSendBuffer(MyApp.getInstance().getDevXinYuanController().getDevXinYuan().checkSlot(slot));
        getLogs().info("33333");
    }

    private void devRunElectric(int field, int slot, int increase) throws LogsEmptyException, LogsSecurityException, LogsUnsupportedOperationException, LogsIOException {
        if (buttonControlCountdown.isShutdown()) {
            buttonControlCountdown.start(5);
        } else {
            buttonControlCountdown.setCountdown(5);
        }

        setTextViewCountdown("開桌完成後點取貨確認", 75);
        isChangeStatus = false;

        SlotStructure slotData = MyApp.getInstance().getSlotData(field, slot);
//        slotData.setLock(true);
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm", Locale.TAIWAN);
        Date timeEpiredDate = new Date();
        if (slotData.getOtherData().has("timeExpired")) {
            try {
                timeEpiredDate = sdf.parse(slotData.getOtherData().getString("timeExpired"));
            } catch (JSONException | ParseException e) {
                getLogs().warning(e);
            }
        }

        String timeEpiredString = sdf.format(timeEpiredDate);
        getLogs().debug("timeEpiredString1:" + timeEpiredString);

        Calendar calendar = Calendar.getInstance();
        calendar.setTime(timeEpiredDate);
        calendar.add(Calendar.HOUR_OF_DAY, increase);
        calendar.add(Calendar.MINUTE, 1);
        timeEpiredDate = calendar.getTime();
        timeEpiredString = sdf.format(timeEpiredDate);
        getLogs().debug("timeEpiredString2:" + timeEpiredString);

        try {
            slotData.getOtherData().put("timeExpired", timeEpiredString);
        } catch (JSONException e) {
            getLogs().warning(e);
        }

        Date now = new Date();
        long diffInMillis = timeEpiredDate.getTime() - now.getTime();

        long diffInSeconds = diffInMillis / 1000; // 總秒數
        int hours = (int) (diffInSeconds / 3600);        // 小時
        int minutes = (int) ((diffInSeconds % 3600) / 60); // 剩下的分鐘
        int seconds = (int) (diffInSeconds % 60);          // 剩下的秒數
        int hoursByDay = (int) (diffInSeconds / 3600 % 24);        // 小時
        int day = (int) (diffInSeconds / 3600 / 24);        // 小時

        getLogs().info("hours:" + hours + " minutes:" + minutes + " seconds:" + seconds);

        DevElectricController devElectricController = new DevElectricController(getHandlerMain());
        DevDigitalDisplayController devDigitalDisplayController = new DevDigitalDisplayController(getHandlerMain());

        devElectricController.devSwitch(slot-1, hours, minutes+2, seconds);
        devDigitalDisplayController.devPut(slot, hours, minutes, seconds);

        getHandlerMain().getHandler().postDelayed(new Runnable() {
            @Override
            public void run() {
                devElectricController.start();

                try {
                    Thread.sleep(300);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }

                devDigitalDisplayController.start();
            }
        }, 200);

        getHandlerMain().start(getClass().getSimpleName(), Option.NEXT_PROCESS_GOODS.getOption(), "next process goods");
    }

    public void setButtonOkText(long countdown) {
        if (countdown <= 0) {
            binding.buttonOk.setText(getContext().getString(R.string.pickup_confirmation));//取貨確認
        } else {
            binding.buttonOk.setText(getContext().getString(R.string.pickup_confirmation)+"(" + countdown + ")");
        }
    }

    public void setTextViewCountdown(long countdown){
        if (countdown <= 0) {
            setTextViewCountdown(getCtx().getString(R.string.pick_up_goods_within_15_seconds_after_pick_up_port_opened), 75);//取貨口開啟15秒內取貨
        } else {
            setTextViewCountdown(getCtx().getString(R.string.pickup_port_open)+"(" + countdown + ")"+getCtx().getString(R.string.pick_up_within), 75);//取貨口開啟,秒內取貨
        }
    }

    public void setTextViewSmall(String message) {
        setTextViewCountdown(message, 60);
    }
    public void setTextViewCountdown(String message, int size) {
        if (isChangeStatus) {
            binding.dispatchtips.setText(message);
            binding.dispatchtips.setTextSize(size);
        }
    }

    public class CloseDialogOnThreadHandler extends HandlerMainCountdown {
        public CloseDialogOnThreadHandler(HandlerMain handlerMain) {
            super(handlerMain);
        }

        @Override
        protected HandlerMain setHandlerMain() {
            return getSrcHandlerMain();
        }

        @Override
        protected void close(HandlerMain handlerMain) {
            handlerMain.start(getClass().getSimpleName(), Option.NEXT_PRODUCT.getOption(), "next product");
        }

        @Override
        protected void execute(long countdown, HandlerMain handlerMain) {
            handlerMain.start(getClass().getSimpleName(), Option.SET_COUNTDOWN_TEXT.getOption(), String.valueOf(countdown));
        }

        @Override
        protected Class<?> setCls() {
            return getClass();
        }
    }
}
